/**
 * Copyright (c) 2009 blurredVision
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include "StdAfx.h"
#include "SoundEffect_OpenAL.h"
#include "audio/SoundBuffer_OpenAL.h"
#include "audio/Audio_OpenAL.h"
#include <algorithm>

namespace openAL {

	SoundEffect_OpenAL::SoundEffect_OpenAL(SoundBuffer_OpenAL* pSoundBuffer): 
		AbstractSound_OpenAL(),
		m_iNumVoices(-1)
	{
		m_pSoundBuffer = pSoundBuffer;		
	}

	
	SoundEffect_OpenAL::~SoundEffect_OpenAL(void) {}
	
	void SoundEffect_OpenAL::stop() {
		
		ALint	iState;	

		SourceVec::iterator it;
		it = m_vSources.begin();
		
		while (it != m_vSources.end()) {
			alGetSourcei((*it), AL_SOURCE_STATE, &iState);		
			if (iState == AL_PLAYING) {
				alSourceStop((*it));
				it = m_vSources.erase(it);
			} else {
				++it;
			}
		}		
	}

	int SoundEffect_OpenAL::getState(){
		ALint	iState;	

		SourceVec::iterator it;
		it = m_vSources.begin();
		
		for (it; it != m_vSources.end(); ++it) {
			alGetSourcei((*it), AL_SOURCE_STATE, &iState);		
			if (iState == AL_PLAYING) {
				return audio::ISOUND_PLAYING;
			}
		}		
		
		return audio::ISOUND_STOPPED;
	}

	
	void SoundEffect_OpenAL::update(const double &dt) {
		
		ALint	iState;
		
		SourceVec::iterator it;
		it = m_vSources.begin();
		
		for (it; it != m_vSources.end(); ++it) {
			
			alGetSourcei((*it), AL_SOURCE_STATE, &iState);
			if (iState != AL_PLAYING) continue; // Do updates only while playing
		
			// Update the volume
			float sfxVol = coreGetAudio()->getSfxVolume(m_bIgnoreMute);
			sfxVol *= m_fVolume;		
			alSourcef((*it), AL_GAIN, sfxVol);		
		}
	}	
	
	bool SoundEffect_OpenAL::play() {
		
		if (m_bLoop) {
			stop();
			m_vSources.clear();
		}

		// Skip playing if the number of voices is reached
		if (m_iNumVoices != -1 && m_iNumVoices <= (int)m_vSources.size()) return false;

		// Get a source from the AudioEngine
		m_sourceID = ((Audio_OpenAL*) coreGetAudio())->requestSource(this, m_iPriority);		
		
		// Put to archiv
		m_vSources.push_back(m_sourceID);
		
		if (m_sourceID == 0) return false;
		
		alGetError();
		ALenum error = AL_NO_ERROR;
		
		// Attach buffer 0 to source
		alSourcei(m_sourceID, AL_BUFFER, m_pSoundBuffer->getBufferID());

		if ((error = alGetError()) != AL_NO_ERROR)
		{
			std::stringstream str;
			str << "Not possible to attach the buffer to source:" << error;
			coreGetLog()->WriteError(str.str(),__FILE__,__LINE__);				
			str.str("");
			str.clear();
			return false;
		}

		// Set Distance-Model parameters
		alSourcef(m_sourceID, AL_REFERENCE_DISTANCE, 20.0f);

		alSourcef(m_sourceID, AL_ROLLOFF_FACTOR, 0.65f);		

		float sfxVol = coreGetAudio()->getSfxVolume(m_bIgnoreMute);
		sfxVol *= m_fVolume;
		alSourcef(m_sourceID, AL_GAIN, sfxVol);

		if (m_bLoop) {
			alSourcei(m_sourceID, AL_LOOPING, AL_TRUE);
		}else{
			alSourcei(m_sourceID, AL_LOOPING, AL_FALSE);
		}

		alSourcePlay(m_sourceID);

		return true;
	}

	void SoundEffect_OpenAL::stealSource(ALuint _source) {
	
		SourceVec::iterator it;
		it = std::find(m_vSources.begin(), m_vSources.end(), _source);
		
		if (it != m_vSources.end()) {
			m_vSources.erase(it);
						
			ALint iState;
			alGetSourcei(_source, AL_SOURCE_STATE, &iState);
			if (iState == AL_PLAYING) {
				alSourceStop(_source);
			}
		}
	}

	void SoundEffect_OpenAL::setNumVoices(int _val)
	{
		m_iNumVoices = _val;
	}

} // namespace
